#include <vector>
#include <cmath>
#include <sstream>
#include "../Function.hpp"
#include "../Curvefitting.h"
#include "../BezierCurve.h"
#include "matplotlibcpp.h"
namespace plt = matplotlibcpp;
using namespace std;
const double pi = acos(-1.);

class F1: public Function {
public:
    dot operator() (double t) const {
        dot dot_t;
        dot_t.x = sqrt(3) * sin(2 * pi * t);
        dot_t.y = (2.0 / 3.0) * (pow(3, 0.25) * sqrt(fabs(sin(2 * pi * t))) - sqrt(3) * cos(2 * pi * t));
        return dot_t;
    }
    dot derivative(double t) const {
        dot dot_t;
        double h = 1e-8;
        double dx = (operator()(t + h).x - operator()(t - h).x) / (2 * h);
        double dy = (operator()(t + h).y - operator()(t - h).y) / (2 * h);
        dot_t.x = dx;
        dot_t.y = dy;        
        return dot_t;
    }
};
class F2 :public Function{
public:
    dot operator() (double t) const {
        dot dot_t;
        dot_t.x = sin(t)+t*cos(t);
        dot_t.y = cos(t)-t*sin(t);
        return dot_t;
    }
    dot derivative(double x) const {
        return {0,0};
    };
};
class F3 :public Function_3{
public:
    dot_3 operator() (double t) const {
        dot_3 dot_t;
        dot_t.x = sin(cos(t))*cos(sin(t));
        dot_t.y = sin(cos(t))*sin(sin(t));
        dot_t.z = cos(cos(t));
        return dot_t;
    }
};
class F4 :public Function{
public:
    dot operator() (double t) const {
        dot dot_t;
        dot_t.x = cos(t);
        dot_t.y = sin(t);
        return dot_t;
    }
    dot derivative(double x) const {
        return {0,0};
    };
};
void r1(){
    vector<dot> points;
    int m_values[] = {10, 40, 160};
    // r1
    for (int m : m_values) {
        stringstream title_stream;
        // 参数t
        // title_stream << "Cubic Spline Curve-fitting of Heart Curve of parameter t (m = " << m << ")";
        // plt::title(title_stream.str());
        Curve_fitting_2_t(F1(), m, 0, 1, 0);
        //plt::save;

        // 参数s
        // title_stream.str("");
        // title_stream << "Cubic Spline Curve-fitting of Heart Curve of parameter s  (m = " << m << ")";
        // plt::title(title_stream.str());
        Curve_fitting_2_s(F1(), m, 0, 1, 0);

        // bezier
        approximateWithBezierCurves(F1(), m, 0, 1);

        title_stream << "Curve-fitting of Heart Curve (m = " << m << ")";
        plt::title(title_stream.str());
        plot_exact_2(F1(),0,1);
    }
}
void r2(){
    vector<dot> points;
    int m_values[] = {10, 40, 160};
    // r2
    for (int m : m_values) {
        // 参数t
        Curve_fitting_2_t(F2(), m, 0, 6*pi, 1, 2, 2, 0, -6*pi);
        //plt::save;
        // 参数s
        Curve_fitting_2_s(F2(), m, 0, 6*pi,1, 1, 2.0/pow(4+36*pi*pi,0.5), 0, -6*pi/pow(4+36*pi*pi,0.5));

        stringstream title_stream;
        title_stream << "Curve-fitting of r_2 (m = " << m << ")";
        plt::title(title_stream.str());
        plot_exact_2(F2(), 0, 6*pi);       
    }
}
void r3(){
    vector<dot> points;
    int m_values[] = {10, 40, 160};
    // r3
    for (int m : m_values) {
        // stringstream title_stream;
        // 参数t
        // title_stream << "Curve-fitting of r_3 of t (m = " << m << ")";
        // plt::title(title_stream.str());
        Curve_fitting_Sphere_t(1, F4(), m, 0, 2*pi, 0); // R=1;采用周期边界条件

        // 参数s
        // title_stream.str("");
        // title_stream << "Curve-fitting of r_3 of s (m = " << m << ")";
        // plt::title(title_stream.str());
        Curve_fitting_Sphere_s(1, F4(), m, 0, 2*pi, 0); // R=1;采用周期边界条件

        // stringstream title_stream;
        // title_stream << "Curve-fitting of r_3 (m = " << m << ")";
        // plt::title(title_stream.str());
        // plot_exact_3(F3(), 0, 2*pi);       
    }
}

int main() {
    r1();
    // r2();
    // r3();
}
